package com.zou.mall.member.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zou.common.utils.R;
import com.zou.common.vo.UserVO;
import com.zou.common.config.ClientInfoHolder;
import com.zou.common.utils.JwtUtil;
import com.zou.mall.member.vo.LoginVO;
import com.zou.mall.member.vo.MemberSearchVO;
import com.zou.mall.member.vo.RegisterVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zou.common.utils.PageUtils;
import com.zou.common.utils.Query;

import com.zou.mall.member.dao.MemberDao;
import com.zou.mall.member.entity.MemberEntity;
import com.zou.mall.member.service.MemberService;

import javax.annotation.Resource;

import static com.zou.mall.member.enums.MemberExceptionEnum.*;

@Slf4j
@Service("memberService")
public class MemberServiceImpl extends ServiceImpl<MemberDao, MemberEntity> implements MemberService {

    private static final String prefix = "USER:";
    private static BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(5);

    @Resource
    MemberDao memberDao;

    @Resource
    JwtUtil jwtUtil;

    @Resource
    private RedisTemplate<String,String> redisTemplate;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<MemberEntity> page = this.page(
                new Query<MemberEntity>().getPage(params),
                new QueryWrapper<MemberEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public R queryList(MemberSearchVO memberSearchVO) {
        log.info("start:{} end:{}",
                memberSearchVO.getStartTime(),memberSearchVO.getEndTime());
        Page<MemberEntity> page = new Page<>(memberSearchVO.getPageNo(),memberSearchVO.getPageSize());
        IPage<MemberEntity> memberEntityIPage = memberDao.selectPage(page, new QueryWrapper<MemberEntity>()
                .eq("mobile", memberSearchVO.getMobile())
                .or().eq("level_id", memberSearchVO.getLevelId())
                .like("username", memberSearchVO.getUsername())
                .or().between("create_time", memberSearchVO.getStartTime(), memberSearchVO.getEndTime()));
        PageUtils pageResult = new PageUtils(memberEntityIPage);
        return R.ok().put("page", pageResult);
    }

    @Override
    public R register(RegisterVO registerVO) {
        R result = new R();
        checkBean(registerVO);
        MemberEntity memberEntity = buildBean(registerVO);
        int insert = memberDao.insert(memberEntity);
        result.put("insert", insert);
        return result;
    }

    @Override
    public R login(LoginVO loginVO) {
        MemberEntity memberEntity = memberDao.selectOne(new QueryWrapper<MemberEntity>()
                .eq("username", loginVO.getLoginAccount())
                .or().eq("mobile", loginVO.getLoginAccount())
                .or().eq("email",loginVO.getLoginAccount()));

        if (Objects.nonNull(memberEntity)) {
            boolean matches = passwordEncoder.matches(loginVO.getPassword(), memberEntity.getPassword());
            if (matches) {
                memberEntity.setPassword("");
                R result = new R();
                result.put("code", 200);
                result.setData(memberEntity);
                result.put("access_token", generateToken(memberEntity));
                return result;
            }
        }
        return R.error(USER_MESSAGE_EXCEPTION.getK(), USER_MESSAGE_EXCEPTION.getV());
    }

    @Override
    public R loginOut() {
        String username = ClientInfoHolder.getClientInfo().getUsername();
        redisTemplate.delete(prefix+username);
        ClientInfoHolder.clear();
        return R.ok();
    }

    private String generateToken(MemberEntity memberEntity) {
        UserVO userVO = new UserVO();
        userVO.setUsername(memberEntity.getUsername());
        userVO.setPhone(memberEntity.getMobile());
        ClientInfoHolder.setClientInfo(userVO);
        try {
            redisTemplate.opsForValue().set(prefix + userVO.getUsername(), JSONUtil.toJsonStr(userVO), 120000, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("redis err:{}", e.toString());
        }

        return jwtUtil.createJWT("1", "登录", userVO.getUsername(), userVO.getPhone());
    }


    private void checkBean(RegisterVO registerVO) {
        Integer countUserName = memberDao.selectCount(new QueryWrapper<MemberEntity>().eq("username", registerVO.getUsername()));
        if (countUserName > 0) {
            throw new RuntimeException(USER_EXIST_EXCEPTION.getV());
        }
        Integer countPhone = memberDao.selectCount(new QueryWrapper<MemberEntity>().eq("mobile", registerVO.getPhone()));
        if (countPhone > 0) {
            throw new RuntimeException(PHONE_NUMBER_EXCEPTION.getV());
        }
    }

    private MemberEntity buildBean(RegisterVO registerVO) {
        MemberEntity memberEntity = new MemberEntity();
        memberEntity.setUsername(registerVO.getUsername());
        memberEntity.setPassword(registerVO.getPassword());
        memberEntity.setMobile(registerVO.getPhone());
        memberEntity.setEmail(registerVO.getEmail());
        String encodePassword = passwordEncoder.encode(registerVO.getPassword());
        memberEntity.setPassword(encodePassword);
        memberEntity.setLevelId(2L);
        return memberEntity;
    }

}